/*
 * neighborhood.js
 */
(function() {

	var BIT = [0, 1, 2, 4, 8, 16, 32, 64, 128];

	function NeighborhoodValue(number, total8, total4) {
		this.number = number;
		this.total8 = total8;
		this.total4 = total4;
	}

	function total(number, until) {
		var c = 0;
		for (var i = 1; i <= until; i++) {
			c += (0 < (number & BIT[i])) ? 1 : 0;
		}
		return c;
	}

	function total8(number) {
		return total(number, 8);
	}
		
	function total4(number) {
		return total(number, 4);
	}

	/*
	 * 
	 */
	var EIGHT_SUM = [];
	var FOUR_SUM = [];
	var EIGHT_SUM_NUMBERS = [];
	var FOUR_SUM_NUMBERS = [];
	
	var NEIGHBORHOOD_ARRAY = [];
	
	for (var n = 0; n < 256; n++) {
		var t8 = total8(n);
		var t4 = total4(n);
		NEIGHBORHOOD_ARRAY[n] = new NeighborhoodValue(n, t8, t4);
	
		if (null == EIGHT_SUM_NUMBERS[t8]) {
			EIGHT_SUM_NUMBERS[t8] = [];
		}
		if (null == FOUR_SUM_NUMBERS[t4]) {
			FOUR_SUM_NUMBERS[t4] = [];
		}
		EIGHT_SUM_NUMBERS[t8].push(n);
		FOUR_SUM_NUMBERS[t4].push(n);
	}

	var Neighborhood = {
		get: function(number) {
			return NEIGHBORHOOD_ARRAY[number];
		},
		getTotals8: function(count) {
			return EIGHT_SUM_NUMBERS[count];
		},
		getTotals4: function(count) {
			return FOUR_SUM_NUMBERS[count];
		},
		rotate: function(number) {
			return ((number & 0x70) << 1) |
				((number & 0x80) >> 3) |
				((number & 0x7) << 1) |
				((number & 0x8) >> 3);
		},

		flip: function(number) {
			return ((number & 0xa) |
				((number & 0xa0) >> 1) |
				((number & 0x50) << 1) |
				(number & 0x4) >> 2) |
				((number & 0x1) << 2);
		},
	};

	akinao.lang.namespace("akinao.ca", {
		Neighborhood: Neighborhood}
	);
})();